package main

import (
	"context"
	"errors"
	"go-devops/WebIde"
	clients "go-devops/client"
	"go-devops/k8s"
	"go-devops/models"
	"io"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

func isLogin() gin.HandlerFunc {
	return func(c *gin.Context) {
		username, err := c.Cookie("username")
		if err != nil || username == "" {
			if c.Request.RequestURI != "/login" && c.Request.RequestURI != "/register" {
				c.Redirect(302, "/login")
			}
		}
		c.Next()
	}
}

func main() {
	// devops数据库连接
	devopsGormClient := clients.InitDevopsGorm()
	// k8s客户端
	k8sClient := clients.InitK8sConfig()
	// router
	r := gin.New()
	// 中间件
	r.Use(isLogin())
	// 模板引擎
	r.LoadHTMLGlob("templates/*")
	// 静态文件
	r.Static("/static", "static/")
	// 页面
	r.GET("/", func(c *gin.Context) {
		// 登录用户信息
		username, _ := c.Cookie("username")
		id, _ := c.Cookie("id")
		idInt, _ := strconv.Atoi(id)
		var userInfo models.UserInfo
		devopsGormClient.Where("id = ?", idInt).Find(&userInfo)
		picture := "static/user/info/picture/" + userInfo.Picture
		// 登录用户issue
		var user_issues []string
		devopsGormClient.Model(&models.IssueModel{}).Select("issue_describe").Where("issue_user = ?", username).Find(&user_issues)
		// webide 关联信息
		var project_member models.ProjectMembersModel
		devopsGormClient.Where("member_name = ?", username).Find(&project_member)
		nodeport := strconv.Itoa(WebIde.GetIngressSvcNodeport())
		url := WebIde.CreateWebVscodeIngress("code-server", "k8scode")
		log.Println(url + ":" + nodeport)
		c.HTML(200, "index.html", gin.H{
			"username":    username,
			"picture":     picture,
			"user_issues": user_issues,
			"has_webide":  project_member.Webide != "",
			"webide":      project_member.Webide,
			"webide_url":  "",
		})
	})
	// devops_user表页面
	{
		r.GET("/devops", func(c *gin.Context) {
			var devopsUserRet []models.DevopsUserModel
			devopsGormClient.Find(&devopsUserRet)
			c.HTML(200, "devops_user.html", gin.H{
				"data": devopsUserRet,
			})
		})
		r.GET("/devops/add", func(c *gin.Context) {
			c.HTML(200, "devops_user_add.html", nil)
		})
		r.POST("/devops/add", func(c *gin.Context) {
			userName := c.PostForm("user_name")
			projectName := c.PostForm("project_name")
			userRole := c.PostForm("user_role")
			devopsUser := models.NewDevopsUserModel(projectName, userName, userRole)
			devopsGormClient.Create(&devopsUser)
			c.Redirect(302, "/devops")
		})
		r.GET("/devops/edit/:id", func(c *gin.Context) {
			id := c.Param("id")
			devopsUser := &models.DevopsUserModel{}
			devopsGormClient.Model(&models.DevopsUserModel{}).Where("devops_user_id = ?", id).Find(&devopsUser)
			c.HTML(200, "devops_user_edit.html", gin.H{
				"devops_user_id":      id,
				"devops_user_name":    devopsUser.DevopsUserName,
				"devops_user_project": devopsUser.DevopsProjectName,
				"devops_user_role":    devopsUser.DevopsProjectName,
			})
		})
		r.POST("/devops/edit/:id", func(c *gin.Context) {
			id := c.Param("id")
			projectName := c.PostForm("devops_project_name")
			userRole := c.PostForm("devops_user_role")
			devopsGormClient.Model(&models.DevopsUserModel{}).
				Where("devops_user_id = ?", id).
				Updates(map[string]interface{}{
					"devops_project_name": projectName,
					"devops_user_role":    userRole,
				})
			c.Redirect(302, "/devops")
		})
		r.GET("/devops/delete/:id", func(c *gin.Context) {
			id := c.Param("id")
			devopsGormClient.Delete(&models.DevopsUserModel{}, id)
			c.Redirect(302, "/devops")
		})
	}
	// 登录用户表逻辑页面
	{
		r.GET("/login", func(c *gin.Context) {
			c.HTML(200, "login.html", nil)
		})
		r.GET("/register", func(c *gin.Context) {
			c.HTML(200, "register.html", nil)
		})
		r.GET("/user", func(c *gin.Context) {
			var userRet []models.UserModel
			devopsGormClient.Find(&userRet)
			c.HTML(200, "user.html", gin.H{"data": userRet})
		})
		r.GET("/user/edit/:id", func(c *gin.Context) {
			id := c.Param("id")
			user := &models.UserModel{}
			devopsGormClient.Model(&models.UserModel{}).Where("id = ?", id).Find(&user)
			c.HTML(200, "user_edit.html", gin.H{"id": id, "username": user.UserName, "message": ""})
		})
		r.POST("/user/edit/:id", func(c *gin.Context) {
			id := c.Param("id")
			password := c.PostForm("password")
			username := c.PostForm("username")
			repeatPassword := c.PostForm("repeatPassword")
			if password == repeatPassword {
				devopsGormClient.Model(&models.UserModel{}).
					Where("id = ?", id).
					Update("password", password)
				c.Redirect(302, "/user")
			} else {
				c.HTML(302, "user_edit.html", gin.H{
					"id":       id,
					"username": username,
					"message":  "password confirm failed, please check",
				})
			}
		})
		r.GET("/user/delete/:id", func(c *gin.Context) {
			id := c.Param("id")
			devopsGormClient.Delete(&models.UserModel{}, id)
			c.Redirect(302, "/user")
		})
		r.POST("/user/register", func(c *gin.Context) {
			username := c.PostForm("user_name")
			password := c.PostForm("password")
			var checkUserName models.UserModel
			devopsGormClient.Where("user_name = ?", username).First(&checkUserName)
			if username != checkUserName.UserName {
				u := models.NewUserModel(username, password)
				devopsGormClient.Create(&u)
				var userModel models.UserModel
				devopsGormClient.Where("user_name = ?", username).First(&userModel)
				id := userModel.Id
				devopsGormClient.Create(models.NewUserInfo(id))
				c.Redirect(302, "/login")
			} else {
				c.HTML(200, "register.html", gin.H{"message": "user already registered"})
			}
		})
		r.POST("/user/login", func(c *gin.Context) {
			username := c.PostForm("user_name")
			password := c.PostForm("password")
			user := &models.UserModel{}
			devopsGormClient.Where("user_name = ?", username).First(user)
			id := strconv.Itoa(user.Id)
			if password == user.Password && password != "" {
				c.SetCookie("username", username, 0, "/", "localhost", false, true)
				c.SetCookie("id", id, 0, "/", "localhost", false, true)
				c.Redirect(http.StatusFound, "/")
			} else {
				c.HTML(200, "login.html", gin.H{"data": "invalid user or wrong password"})
			}
		})
		r.GET("/user/logout", func(c *gin.Context) {
			c.SetCookie("username", "", -1, "/", "localhost", false, true)
			c.Redirect(http.StatusFound, "/login")
		})
		r.GET("/user/listall", func(c *gin.Context) {
			var userList []string
			devopsGormClient.Model(&models.UserModel{}).Select("user_name").Find(&userList)
			c.JSON(200, gin.H{"user_list": userList})
		})
	}
	// 登录用户信息
	{
		r.GET("/user/info", func(c *gin.Context) {
			id, _ := c.Cookie("id")
			userName, _ := c.Cookie("username")
			idInt, _ := strconv.Atoi(id)
			var userInfoModel models.UserInfo
			devopsGormClient.Where("id = ?", idInt).First(&userInfoModel)
			email := userInfoModel.Email
			c.HTML(200, "user_info.html", gin.H{
				"id":        id,
				"user_name": userName,
				"email":     email,
				"picture":   userInfoModel.Picture,
			})
		})
		r.POST("/user/info/upload/picture", func(c *gin.Context) {
			picture, err := c.FormFile("picture")
			if err != nil {
				log.Fatal(err)
			}
			pictureFilePath := "static/user/info/picture/" + picture.Filename
			targetFile, err := os.OpenFile(pictureFilePath, os.O_WRONLY|os.O_CREATE, 0666)
			if err != nil {
				log.Fatal(err)
			}
			defer targetFile.Close()
			pictureFile, err := picture.Open()
			if err != nil {
				log.Fatal(err)
			}
			_, err = io.Copy(targetFile, pictureFile)
			if err != nil {
				log.Fatal(err)
			}
			id, err := c.Cookie("id")
			if err != nil {
				log.Fatal(err)
			}
			idInt, _ := strconv.Atoi(id)
			devopsGormClient.Model(&models.UserInfo{}).
				Where("id = ?", idInt).
				Update("picture", picture.Filename)
			c.HTML(302, "user_info.html", gin.H{
				"picture": picture.Filename,
			})
		})
		r.POST("/user/email/edit/:id", func(c *gin.Context) {
			id, _ := c.Cookie("id")
			idInt, _ := strconv.Atoi(id)
			email := c.PostForm("email")
			var userInfo models.UserInfo
			devopsGormClient.Model(&userInfo).Where("id = ?", idInt).Update("email", email)
			c.Redirect(302, "/user/info")
		})
	}
	// 项目
	{
		r.GET("/project", func(c *gin.Context) {
			var projectRet []models.ProjectModel
			devopsGormClient.Find(&projectRet)
			c.HTML(200, "project.html", gin.H{"data": projectRet})
		})
		r.POST("/project/add", func(ctx *gin.Context) {
			projectName := ctx.PostForm("projectName")
			projectDescribe := ctx.PostForm("projectDescribe")
			newProject := models.NewProjectModel(projectName, projectDescribe)
			newProject.CreateTime = time.Now().Format("2006-01-02 15:04:05")
			devopsGormClient.Create(newProject)
			if err := k8s.CreateNs(k8sClient, projectName); err != nil {
				log.Fatal(err)
			}
			ctx.Redirect(302, "/project")
		})
		r.GET("/project/delete/:id", func(ctx *gin.Context) {
			projectId := ctx.Param("id")
			var project models.ProjectModel
			devopsGormClient.Where("project_id = ?", projectId).Find(&project)
			devopsGormClient.Delete(&models.ProjectModel{}, projectId)
			err := k8sClient.CoreV1().Namespaces().Delete(context.Background(), project.ProjectName, metav1.DeleteOptions{})
			if err != nil {
				log.Fatal(err)
			}
			ctx.Redirect(302, "/project")
		})
	}
	// 项目成员
	{
		r.GET("/project/members/:name", func(ctx *gin.Context) {
			project_name := ctx.Param("name")
			var project models.ProjectModel
			devopsGormClient.Where("project_name = ?", project_name).Find(&project)
			project_id := project.ProjectId
			var members []models.ProjectMembersModel
			devopsGormClient.Where("project_id = ?", project_id).Find(&members)
			ctx.HTML(200, "project_members.html", gin.H{"data": members, "project_name": project_name})
		})
		r.GET("/project/members/add/:project_name", func(ctx *gin.Context) {
			projectName := ctx.Param("project_name")
			ctx.HTML(200, "members_add.html", gin.H{"project_name": projectName})
		})
		r.POST("/project/members/add/:project_name", func(ctx *gin.Context) {
			// 表单内容
			projectName := ctx.Param("project_name")
			memberName := ctx.PostForm("memberName")
			memberRole := ctx.PostForm("memberRole")
			webide := ctx.PostForm("webide")
			// 判断成员角色是否为 前端、后端
			if memberRole == "前端" || memberRole == "后端" {
				// 判断web ide是否vscode
				if webide == "vscode" {
					WebIde.CreateWebVscode(memberName+"-vscode", projectName)
				} else if webide == "goland" {

				} else if webide == "idea" {

				}
			}
			// 通过项目名称，查询项目id
			var project models.ProjectModel
			devopsGormClient.Where("project_name = ?", projectName).Find(&project)
			projectId := project.ProjectId
			// 创建新的project_member
			member := models.NewProjectMembersModel(projectId, memberName, memberRole, webide, time.Now().Format("2006-01-02 15:04:05"))
			member.ProjectId = projectId
			devopsGormClient.Create(&member)
			// 跳转
			ctx.Redirect(302, "/project/members/"+projectName)
		})
	}
	// 事务
	{
		r.GET("/issue", func(c *gin.Context) {
			var issueRet []models.IssueWithProjectName
			devopsGormClient.Model(&issueRet).
				Select("issue.*, CASE WHEN issue.issue_solve = 0 THEN '未解决' WHEN issue.issue_solve = 1 THEN '已解决' END AS issue_status, project.project_name ").
				Joins("LEFT JOIN project ON issue.project_id = project.project_id").
				Scan(&issueRet)
			c.HTML(200, "issue.html", gin.H{"data": issueRet})
		})
		r.GET("/issue/add", func(c *gin.Context) {
			var projects []models.ProjectModel
			devopsGormClient.Find(&projects)
			c.HTML(200, "issue_add.html", gin.H{"projects": projects})
		})
		r.POST("/issue/add", func(c *gin.Context) {
			issueUser, _ := c.Cookie("username")
			projectId := c.PostForm("project_id")
			projectIdInt, _ := strconv.Atoi(projectId)
			issueDescribe := c.PostForm("issue_describe")
			issueDetail := c.PostForm("issue_detail")
			devopsGormClient.Create(
				models.NewIssueModel(
					models.WithIssueUser(issueUser),
					models.WithProjectId(projectIdInt),
					models.WithIssueDescribe(issueDescribe),
					models.WithIssueDetail(issueDetail),
				))
			c.Redirect(302, "/issue")
		})
		r.GET("/issue/delete/:id", func(c *gin.Context) {
			id := c.Param("id")
			devopsGormClient.Delete(&models.IssueModel{}, id)
			c.Redirect(302, "/issue")
		})
	}
	// k8s
	{
		r.GET("/k8s", func(c *gin.Context) {
			nsList := k8s.GetNsList(k8sClient)
			allDepList := make([]string, 0)
			allIngressList := make([]string, 0)
			for _, ns := range nsList {
				depList := k8s.GetDeploymentList(k8sClient, ns)
				ingressList := k8s.GetIngress(k8sClient, ns)
				for _, dep := range depList {
					allDepList = append(allDepList, dep)
				}
				for _, ingress := range ingressList {
					allIngressList = append(allIngressList, ingress)
				}
			}
			c.HTML(200, "k8s.html", gin.H{
				"ns_list":          nsList,
				"all_dep_list":     allDepList,
				"all_ingress_list": allIngressList,
			})
		})
		r.GET("/k8s/ns", func(c *gin.Context) {
			nsList := k8s.GetNsList(k8sClient)
			c.JSON(200, gin.H{"ns_list": nsList})
		})
		r.GET("/k8s/deployments/get/:ns", func(c *gin.Context) {
			ns := c.Param("ns")
			depList := k8s.GetDeploymentList(k8sClient, ns)
			c.JSON(200, gin.H{
				"dep_list": depList,
			})
		})
		r.GET("/k8s/test", func(c *gin.Context) {
			nsList := k8s.GetNsList(k8sClient)
			c.HTML(200, "k8s_test.html", gin.H{
				"ns_list": nsList,
			})
		})
		r.GET("/k8s/ingress/:ns", func(c *gin.Context) {
			ns := c.Param("ns")
			list, err := k8sClient.NetworkingV1().Ingresses(ns).List(context.Background(), metav1.ListOptions{})
			ingressList := make([]string, 0)
			if err != nil {
				log.Fatal(err)
			}
			for _, item := range list.Items {
				ingressList = append(ingressList, item.Name)
			}
			c.JSON(200, gin.H{"ingress_list": ingressList})
		})
		r.GET("/k8s/ns/delete/:ns", func(c *gin.Context) {
			ns := c.Param("ns")
			err := k8sClient.CoreV1().Namespaces().Delete(context.Background(), ns, metav1.DeleteOptions{})
			if err != nil {
				log.Fatal(err)
			}
			c.Redirect(302, "/project")
		})
	}
	// scrum 冲刺
	{
		r.GET("/scrum", func(c *gin.Context) {
			var scrumList []models.ScrumModel
			devopsGormClient.Where("scrum_status != '已完成'").Find(&scrumList)
			var allocateUserNames []string
			devopsGormClient.Model(&models.UserModel{}).Select("user_name").Find(&allocateUserNames)
			user, _ := c.Cookie("username")
			c.HTML(200, "scrum.html", gin.H{
				"scrum_list":    scrumList,
				"scrum_user":    user,
				"allocate_user": allocateUserNames,
			})
		})
		r.POST("/scrum/add", func(c *gin.Context) {
			scrumDetail := c.PostForm("scrum_detail")
			scrumUser, _ := c.Cookie("username")
			scrumStatus := c.PostForm("scrum_status")
			allocateUser := c.PostForm("allocate_user")
			expirationDatetime := c.PostForm("expiration_datetime")
			scrum := models.NewScrumModel(scrumDetail, scrumUser, scrumStatus, allocateUser, expirationDatetime)
			scrum.CreateTime = time.Now().Format("2006-01-02 15:04:05")
			devopsGormClient.Create(scrum)
			c.Redirect(302, "/scrum")
		})
		r.GET("/scrum/status/edit/:value/:id", func(c *gin.Context) {
			value := c.Param("value")
			id := c.Param("id")
			devopsGormClient.Model(&models.ScrumModel{}).
				Where("scrum_id = ?", id).
				Update("scrum_status", value)
		})
		r.GET("/scrum/allocate_user/edit/:value/:id", func(c *gin.Context) {
			value := c.Param("value")
			id := c.Param("id")
			devopsGormClient.Model(&models.ScrumModel{}).
				Where("scrum_id = ?", id).
				Update("allocate_user", value)
		})
		r.GET("/scrum/edit/:id", func(c *gin.Context) {
			id := c.Param("id")
			log.Println(id)
		})
		r.GET("/scrum/delete/:id", func(c *gin.Context) {
			id := c.Param("id")
			devopsGormClient.Delete(&models.ScrumModel{}, id)
			c.Redirect(302, "/scrum")
		})
	}
	// 测试api
	r.GET("/api", func(c *gin.Context) {
		c.JSON(200, gin.H{"data": "api"})
	})
	api := r.Group("/api/")
	{
		api.POST("/devops/user/add", func(c *gin.Context) {
			pName := c.PostForm("devops_project_name")
			uName := c.PostForm("devops_user_name")
			uRole := c.PostForm("devops_user_role")
			devopsUser := models.NewDevopsUserModel(pName, uName, uRole)
			devopsGormClient.Create(&devopsUser)
			c.JSON(200, gin.H{
				"data": "success",
			})
		})
		api.GET("/devops/user/listall", func(c *gin.Context) {
			var devopsUserRet []models.DevopsUserModel
			result := devopsGormClient.Find(&devopsUserRet)
			if result.Error != nil {
				c.JSON(403, gin.H{
					"data": "error",
				})
			}
			c.JSON(200, gin.H{
				"data": devopsUserRet,
			})
		})
		api.GET("/devops/user/list/:devops_user_id", func(c *gin.Context) {
			devops_user_id := c.Param("devops_user_id")
			var devopsUser models.DevopsUserModel
			devopsGormClient.Where("devops_user_id = ?", devops_user_id).First(&devopsUser)
			c.JSON(200, gin.H{
				"data": devopsUser,
			})

		})
		// 这里是http://localhost:8081/devops/user/edit/1 然后 用json请求
		api.PUT("/devops/user/edit/:devops_user_id", func(c *gin.Context) {
			devopsUserID := c.Param("devops_user_id")
			type UpdateUser struct {
				DevopsProjectName string `json:"devops_project_name"`
				DevopsUserRole    string `json:"devops_user_roel"`
			}
			var updateUser UpdateUser
			if err := c.ShouldBindJSON(&updateUser); err != nil {
				log.Println(err)
			}
			result := devopsGormClient.Model(&models.DevopsUserModel{}).
				Where("devops_user_id = ?", devopsUserID).
				Update("devops_project_name", updateUser.DevopsProjectName).
				Update("devops_user_role", updateUser.DevopsUserRole)
			if result.Error != nil {
				if errors.Is(result.Error, gorm.ErrRecordNotFound) {
					c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
				} else {
					c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user"})
				}
			}
			c.JSON(http.StatusOK, gin.H{"message": "User updated successfully."})
		})
		api.DELETE("/devops/user/delete/:devops_user_id", func(c *gin.Context) {
			devopsUserId := c.Param("devops_user_id")
			result := devopsGormClient.Where("devops_user_id = ?", devopsUserId).Delete(&models.DevopsUserModel{})
			if result.Error == nil {
				c.JSON(200, gin.H{"data": "success"})
			} else {
				c.JSON(403, gin.H{"data": "fail"})
			}
		})
		api.GET("/user/listall", func(c *gin.Context) {
			var userRet []models.UserModel
			result := devopsGormClient.Find(&userRet)
			if result.Error != nil {
				c.JSON(403, gin.H{
					"data": "error",
				})
			}
			c.JSON(200, gin.H{
				"data": userRet,
			})
		})
	}
	r.Run(":8081")
}
